/*
  重现Promise的要点：
  1.使用new进行声明，所以MyPromise应该是一个类
  2.需要一个立即执行的执行器
  3.Promise中的三种状态 fulfilled rejected pedding
  4.resolve与reject 用来更改状态，且状态只能更改一次
  5.then方法用来判断状态来读取相应的回调函数
  6.异步函数需要储存
  7.多个then方法需要数组进行储存，然后再依次调用
  8.链式调用中，上一个then方法的返回值需要作为下一个then方法的参数
  9.上一个then方法的返回值可能是promise对象，，普通值可以直接作为下一个的参数，promise对象的话需要根据其返回的结果去决定调用成功或者失败回调
  10.当前Promise对象的then方法中不能返回当前的promise对象
  11.执行器出现错误的时候，返回失败回调函数
  12.then方法出错的时候，需要在下一个then方法的失败回调函数中捕获到
  13.then方法中可以不放参数
  14.all()方法实现
  15.resoleve方法实现
  16.finally方法实现
  17.catch方法实现

*/
const PENDING = 'pending' //等待
const FULFILLED = 'fulfilled' //成功
const REJECTED = 'rejected' //失败
function isPending(status){
    return status !== PENDING 
}

class MyPromise{
    constructor(executor){
        try {
            executor(this.resolve,this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    status = PENDING
    value = undefined; //成功后的值
    reason = undefined; //失败后的原因
    successCallBackList = []; //成功回调数组
    failCallBackList = []; //失败回调数组
    resolve = value =>{
        if(isPending(this.status))return
        this.status = FULFILLED
        this.value = value
        while(this.successCallBackList.length){
            this.successCallBackList.shift()()
        }//处理异步函数，将储存的成功回调进行调用
    }
    reject = reason =>{
        if(isPending(this.status))return
        this.status = REJECTED
        this.reason = reason
        while(this.failCallBackList.length){
            this.failCallBackList.shift()()
        }//处理异步函数，将储存的失败回调进行调用
    }
    //判断是否等待，等待状态才可进行更改，否则直接返回
    
    then(sCallback,fCallback){
        sCallback = sCallback?sCallback:value=>value
        fCallback = fCallback?fCallback:reason=>{throw reason}
        let newPromise = new MyPromise((resolve,reject)=>{
            if(this.status === FULFILLED){
                setTimeout(()=>{
                    try {
                        let newRes = sCallback(this.value) //成功回调
                        resolvePromise(newPromise,newRes,resolve,reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)//为了获取到newPromise，将这块代码变成异步代码，从而使newPromise已经正常的生成
            }else if(this.status === REJECTED){
                setTimeout(()=>{
                    try {
                        let newRes = fCallback(this.reason) //失败回调
                        resolvePromise(newPromise,newRes,resolve,reject)
                    } catch (error) {
                        reject(error)
                    }
                },0)
            }else{
                //等待时候，存储回调函数
                this.successCallBackList.push(()=>{
                    setTimeout(()=>{
                        try {
                            let newRes = sCallback(this.value) //成功回调
                            resolvePromise(newPromise,newRes,resolve,reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    },0)
                })
                this.failCallBackList.push(()=>{
                    setTimeout(()=>{
                        try {
                            let newRes = fCallback(this.reason) //失败回调
                            resolvePromise(newPromise,newRes,resolve,reject)
                        } catch (error) {
                            reject(error)
                        }
                    },0)
                })
            }
        });
        return newPromise
    }
    finally(callback){
        return this.then((value)=>{
            return MyPromise.resolve(callback()).then(()=>value)
        },(reason)=>{
            return MyPromise.resolve(callback()).then(()=>{ throw reason })
        })
    }
    catch(faiCallback){
        return this.then(undefined,faiCallback)
    }
    static all(array){
        let result = []
        let index = 0
        return new MyPromise((resolve,reject)=>{
            function addData(key,value){
                result[key] = value
                index ++ 
                if(index === array.length){
                    resolve(result)
                }
            }
            for(let i = 0;i<array.length;i++){
                let current = array[i]
                if(current instanceof MyPromise){
                    //promise
                    current.then((value)=>{
                        addData(i,value)
                    },(reason)=>{
                        reject(reason)
                    })
                }else{
                    //普通值
                    addData(i,array[i])
                }
            }
        })
    }
    static resolve(value){
        if(value instanceof MyPromise){
            return value
        }
        return new MyPromise(resolve=>resolve(value))
    }
}
function resolvePromise(newPromise,newRes,resolve,reject){
    if(newPromise === newRes){
        reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(newRes instanceof MyPromise){
        newRes.then(resolve,reject)
    }else{
        resolve(newRes)
    }
}
let promise = new MyPromise((resolve,reject)=>{
    // setTimeout(()=>{
    //     resolve('成功')
    // },1000)
    // throw new Error('exe')
    // resolve('成功')
    reject('失败')
})
function p1 (){
    return new MyPromise((resolve,reject)=>{
        setTimeout(() => {
            resolve('p1')
        }, 1000);
    })
}
function p2 (){
    return new MyPromise((resolve,reject)=>{
        // reject('p2 reject')
        resolve('resovel,p2')
    })
}
p2().then(res=>{
    console.log(res)
})
.catch(err=>{
    console.log(err)
})
// p2().finally(()=>{
//     console.log('fin')
//     return p1();
// }).then(res=>{
//     console.log("111")
//     console.log(res)
// },err=>{
//     console.log(err)
// })
// MyPromise.all(['a',p1(),p2(),'b']).then(res=>{
//     console.log(res)
// })
// MyPromise.resolve(10).then(res=>console.log(res))
// MyPromise.resolve(p1()).then(res=>console.log(res))
